﻿using System;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Forms;
using DevExpress.Utils.Design;
using DevExpress.XtraEditors;
using XCI.Core;
using XCI.Helper;

namespace XCI.Windows
{
    public class EditDataLayoutControlPlus : DataLayoutControlPlus
    {
        private LoadingMask loading;

        /// <summary>
        /// 参数
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public EditFormArgs Args { get; set; }

        [Category("XCI"), Description("连续新增复选控件")]
        [SmartTagProperty("连续新增复选控件", "XCI", SmartTagActionType.RefreshAfterExecute)]
        public BaseEdit ContinueCreateCheck { get; set; }

        [Category("XCI"), Description("重置表单复选控件")]
        [SmartTagProperty("重置表单复选控件", "XCI", SmartTagActionType.RefreshAfterExecute)]
        public BaseEdit ResetFormCheck { get; set; }

        [Category("XCI"), Description("编辑表单标题"),DefaultValue(null)]
        public string FormTitle { get; set; }

        [Category("XCI"), Description("Loading面板容器"),DefaultValue(null)]
        public Control LoadingOwner { get; set; }

        [Category("XCI"), Description("绑定表单事件")]
        public event EventHandler<EditFormPanelBindingEventArgs> BindingForm;

        [Category("XCI"), Description("验证表单事件")]
        public event EventHandler<EditFormPanelValidateEventArgs> ValidateForm;

        [Category("XCI"), Description("保存表单之前事件")]
        public event EventHandler<EditFormPanelBeforeSaveEventArgs> BeforeSaveForm;

        [Category("XCI"), Description("保存表单事件")]
        public event EventHandler<EditFormPanelSaveEventArgs> SaveForm;

        [Category("XCI"), Description("关闭表单事件")]
        public event EventHandler<EventArgs> CloseForm;

        [Category("XCI"), Description("重置表单事件")]
        public event EventHandler<EditFormPanelResetEventArgs> ResetForm;
         

        protected override void OnCreateControl()
        {
            base.OnCreateControl();
            if (WinFormHelper.IsDesignMode()) return;
            loading = new LoadingMask();
            if (ContinueCreateCheck != null && ContinueCreateCheck is CheckEdit ckContinue)
            {
                ckContinue.CheckedChanged += (o, e) =>
                {
                    if (ResetFormCheck != null)
                    {
                        ResetFormCheck.Visible = (bool)ContinueCreateCheck.EditValue;
                    }
                };
            }
        }

        /// <summary>
        /// 读取当前行或者指定Id的数据并绑定到控件
        /// </summary>
        public async Task BindingModelAsync()
        {
            if (WinFormHelper.IsDesignMode()) return;

            if (ContinueCreateCheck != null && Args != null)
            {
                ContinueCreateCheck.Visible = Args.Created;
            }
            if (ContinueCreateCheck != null && ResetFormCheck != null)
            {
                ResetFormCheck.Visible = (bool)ContinueCreateCheck.EditValue;
            }
            var ownerForm = this.FindForm();
            if (ownerForm != null && Args != null && !string.IsNullOrEmpty(FormTitle))
            {
                ownerForm.Text = WinFormHelper.GetEditFormTitle(Args.Created, FormTitle);
            }

            var args = new EditFormPanelBindingEventArgs { Args = Args };
            BindingForm?.Invoke(this, args);
            
            Control owner = LoadingOwner ?? this.FindForm();
            await loading.ShowAsync(owner, async () =>
             {
                 await BindingDataAsync();
                 if (args.Task != null)
                 {
                     await args.Task.Invoke();
                 }
                 await BindingEditValueAsync();
             });
        }

        public async Task SaveModelAsync()
        {
            if (WinFormHelper.IsDesignMode()) return;
            if (SaveForm == null) throw new ArgumentNullException(nameof(SaveForm));
            this.ValidateChildren();

            object model = DataSource;
            if (DataSource != null && DataSource is BindingSource bindingSource)
            {
                model = bindingSource.DataSource;
            }

            bool validateResult = false;
            if (ValidateForm != null)
            {
                var validateArgs = new EditFormPanelValidateEventArgs { Args = Args, Model = model };
                ValidateForm.Invoke(this, validateArgs);
                validateResult = validateArgs.Result;
            }
            else if (model != null)
            {
                validateResult = App.Validator.ValidateObject(model);
            }

            if (!validateResult) return;

            Control owner = LoadingOwner ?? this.FindForm();
            if (BeforeSaveForm != null)
            {
                var beforeSaveArgs = new EditFormPanelBeforeSaveEventArgs { Args = Args, Model = model };
                BeforeSaveForm.Invoke(this, beforeSaveArgs);
                await loading.ShowAsync(owner, async () =>
                {
                    await beforeSaveArgs.Task.Invoke();
                });
            }
            
            this.ValidateChildren();
            var saveArgs = new EditFormPanelSaveEventArgs { Args = Args, Model = model };
            SaveForm?.Invoke(this, saveArgs);
            if (saveArgs.Task == null) throw new ArgumentNullException(nameof(saveArgs.Task));
            
            BoolResult saveResult = null;
            await loading.ShowAsync(owner, async () => saveResult = await saveArgs.Task.Invoke());
            if (saveResult.Fail)
            {
                if (saveArgs.ShowErrorBox && !string.IsNullOrEmpty(saveResult.Msg)) MessageBoxHelper.ShowError(saveResult.Msg);
                return;
            }

            if (ContinueCreateCheck != null && (bool)ContinueCreateCheck.EditValue)
            {
                if (!string.IsNullOrEmpty(saveArgs.SuccessMessage))
                {
                    MessageBoxHelper.ShowMessage(saveArgs.SuccessMessage);
                }
                //连续新增
                if (ResetFormCheck != null && (bool)ResetFormCheck.EditValue)
                {
                    ResetForm?.Invoke(this, new EditFormPanelResetEventArgs { Args = Args, Model = model });
                }
            }
            else
            {
                if (CloseForm != null)
                {
                    CloseForm.Invoke(this, EventArgs.Empty);
                }
                else
                {
                    Form ownerForm = this.FindForm();
                    if (ownerForm != null) ownerForm.DialogResult = DialogResult.OK;
                }
            }
        }
    }

    public class EditFormArgs
    {
        public bool Created { get; set; }
        public string Id { get; set; }
        public string ParentId { get; set; }
        public string Code { get; set; }

        public static EditFormArgs Create()
        {
            return new EditFormArgs { Created = true };
        }
        public static EditFormArgs CreateTree(string parentId)
        {
            return new EditFormArgs { Created = true, ParentId = parentId };
        }
        public static EditFormArgs Edit(string id)
        {
            return new EditFormArgs { Created = false, Id = id };
        }
        public static EditFormArgs EditTree(string id, string parentId)
        {
            return new EditFormArgs { Created = false, Id = id, ParentId = parentId };
        }
    }

    public class EditFormPanelBindingEventArgs : EventArgs
    {
        public EditFormArgs Args { get; set; }
        public bool Created => Args?.Created ?? true;
        public string Id => Args?.Id ?? null;
        public string ParentId => Args?.ParentId ?? null;
        public Func<Task> Task { get; set; }
    }

    public class EditFormPanelValidateEventArgs : EventArgs
    {
        public EditFormArgs Args { get; set; }
        public object Model { get; set; }
        public bool Result { get; set; } = true;
    }

    public class EditFormPanelBeforeSaveEventArgs : EventArgs
    {
        public EditFormArgs Args { get; set; }
        public object Model { get; set; }
        public Func<Task> Task { get; set; }
    }
    public class EditFormPanelSaveEventArgs : EventArgs
    {
        public EditFormArgs Args { get; set; }
        public object Model { get; set; }
        public bool ShowErrorBox { get; set; } = true;
        public string SuccessMessage { get; set; } = "保存成功";
        public Func<Task<BoolResult>> Task { get; set; }
    }

    public class EditFormPanelResetEventArgs : EventArgs
    {
        public EditFormArgs Args { get; set; }
        public object Model { get; set; }
    }
}